import { PhysicsSystem2D, Vec2, _decorator, Component, Node, Label, Vec3, input, Input, EventMouse, RigidBody2D, Collider2D, Contact2DType, tween, view, BoxCollider2D } from 'cc';
import { Box } from './Box';
import { Player } from './Player';
import { ResLoader } from '../../common/res/ResLoader';

const { ccclass, property } = _decorator;

enum BlockType {
    BT_NONE,
    BT_STONE,
}

enum GameState {
    GS_INIT,
    GS_PLAYING,
    GS_END,
}

export const BLOCK_SIZE = 40;

@ccclass('Play')
export class Play extends Component {

    static R(loader: ResLoader) {
        loader.addUI(Player);
        loader.addUI(Box);
    }

    @property({ type: Label })
    public stepsLabel: Label | null = null;

    private player: Player = null;
    private roadLength: number = 50;
    private _road: BlockType[] = [];
    private playerHealth: number = 1000;
    private boxSpeed: number = 10;
    private enemyIntervalId: number = -1;

    onLoad() {
        // 启用物理系统
        PhysicsSystem2D.instance.enable = true;
        // 监听物理接触事件
        PhysicsSystem2D.instance.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
    }

    async start() {
        this.initPlayer();
        // this.initBoxRoad();
        this.playering();

        if (this.stepsLabel) {
            this.stepsLabel.string = `Health: ${this.playerHealth}`;
        }

        this.enemyIntervalId = setInterval(() => {
            this.spawnEnemy();
        }, 10000);
    }

    initPlayer() {
        this.player = game.ui.instantiate(Player);
        this.player.node.setPosition(Vec3.ZERO);
        this.player.node.setParent(game.ui.playerCanvas.node);
        this.player.node.on('JumpEnd', this.onPlayerJumpEnd, this);
    }

    initBoxRoad() {
        this._road = [BlockType.BT_STONE];

        for (let i = 1; i < this.roadLength; i++) {
            if (this._road[i - 1] === BlockType.BT_NONE) {
                this._road.push(BlockType.BT_STONE);
            } else {
                this._road.push(Math.floor(Math.random() * 2));
            }
        }

        for (let j = 0; j < this._road.length; j++) {
            let block = this.spawnBlockByType(this._road[j]);
            if (block) {
                game.ui.playerCanvas.node.addChild(block);
                block.setPosition(j * BLOCK_SIZE, 0, 0);
            }
        }
    }

    spawnBlockByType(type: BlockType): Node | null {
        switch (type) {
            case BlockType.BT_STONE:
                return game.ui.instantiate(Box).node;
            default:
                return null;
        }
    }

    playering() {
        if (this.stepsLabel) {
            this.stepsLabel.string = '0';
        }

        setTimeout(() => {
            if (this.player) {
                this.player.setInputActive(true);
            }
        }, 100);

        input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
    }

    onMouseUp(event: EventMouse) {
        if (event.getButton() === EventMouse.BUTTON_LEFT && this.player) {
            this.player.jump(); // 触发跳跃动作
        }
    }

    onPlayerJumpEnd(moveIndex: number) {
        if (this.stepsLabel) {
            this.stepsLabel.string = '' + (moveIndex >= this.roadLength ? this.roadLength : moveIndex);
        }
        this.checkResult(moveIndex);
        this.takeDamage(10); // 跳跃造成固定伤害
    }

    checkResult(moveIndex: number) {
        if (moveIndex >= this.roadLength) {
            this.setCurState(GameState.GS_INIT);
            return;
        }
        if (this._road[moveIndex] === BlockType.BT_NONE) {
            this.setCurState(GameState.GS_INIT);
        }
    }

    takeDamage(damage: number) {
        this.playerHealth -= damage;
        if (this.stepsLabel) {
            this.stepsLabel.string = `Health: ${Math.max(this.playerHealth, 0)}`;
        }
        if (this.playerHealth <= 0) {
            this.setCurState(GameState.GS_END);
        }
    }

    setCurState(value: GameState) {
        switch (value) {
            case GameState.GS_INIT:
                break;
            case GameState.GS_PLAYING:
                this.playering();
                break;
            case GameState.GS_END:
                if (this.enemyIntervalId !== -1) {
                    clearInterval(this.enemyIntervalId);
                    this.enemyIntervalId = -1;
                }
                console.log("Game Over");
                break;
        }
    }

    spawnEnemy() {
        let enemy = this.spawnBlockByType(BlockType.BT_STONE);
        if (enemy) {
            let randomX = Math.random() * (view.getVisibleSize().width - view.getVisibleSize().width / 5) + (-view.getVisibleSize().width / 2);
            enemy.setPosition(randomX, view.getVisibleSize().height / 2, 0);
            game.ui.playerCanvas.node.addChild(enemy);

            let rigidbody = enemy.addComponent(RigidBody2D);
            rigidbody.gravityScale = 0;

            let collider = enemy.addComponent(BoxCollider2D);
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);

            tween(enemy)
                .repeatForever(
                    tween().call(() => {
                        if (this.player && enemy.isValid) {
                            const direction = Vec3.subtract(new Vec3(), this.player.node.position, enemy.position).normalize();
                            rigidbody.linearVelocity = new Vec2(direction.x * this.boxSpeed, direction.y * this.boxSpeed);
                        }
                    })
                )
                .start();
        }
    }

    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
        if (otherCollider.node === this.player?.node) {
            this.takeDamage(10);
        }
    }
}